#!/usr/bin/env python

import Image,ImageChops,ImageStat
import StringIO
import time, datetime, urllib2, base64, os, threading

import mailer # pip install mailer

from threading import Event, Thread

# Repeated timer interval class
# Copyright (c) 2009 Geoffrey Foster
class RepeatTimer(Thread):
    def __init__(self, interval, function, iterations=0, args=[], kwargs={}):
        Thread.__init__(self)
        self.interval = interval
        self.function = function
        self.iterations = iterations
        self.args = args
        self.kwargs = kwargs
        self.finished = Event()

    def run(self):
        count = 0
        while not self.finished.is_set() and (self.iterations <= 0 or count < self.iterations):
            self.finished.wait(self.interval)
            if not self.finished.is_set():
                self.function(*self.args, **self.kwargs)
                count += 1

    def cancel(self):
        self.finished.set()

options = {
    'camera': 'camera 2',   		# common name for camera
    'login':'admin',        		# login for snapshot.cgi basic auth
    'password':'***********',  		# password for snapshot.cgi basic auth
    'host':'192.168.1.100',  		# camera IP or domain
    'path':'camera/2.snapshot', 	# snapshot jpg path
    'sensitivity':10,       		# motion RMS sensitivity
    'photos_in_chain':1,    		# photos after no motion registered
    'save_path':'/var/www/security/snapshots/', # path for saving our images
    'schedule': {           		# schedule for making alarm photos and sending email/sms
        'Mon': [0,1,2,3,4,5,6,7,8,19,20,21,22,23],
        'Tue': [0,1,2,3,4,5,6,7,8,19,20,21,22,23],
        'Wed': [0,1,2,3,4,5,6,7,8,19,20,21,22,23],
        'Thu': [0,1,2,3,4,5,6,7,8,19,20,21,22,23],
        'Fri': [0,1,2,3,4,5,6,7,8,19,20,21,22,23],
        'Sat': [0,1,2,3,4,5,6,7,8,19,20,21,22,23],
        'Sun': [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],
    },
    'smtp':{                		# mailer settings
        'host': 'myemail.com',
        'port': '25',
        'username': 'robot@myemail.com',
        'password': '******************'
    }
}

sc_chain_array = []

def mail_timer():
    global sc_chain_array
    global options

    if len(sc_chain_array) > 0:
        message = mailer.Message()
        message.From = "robot@myemail.com"
        message.To = "user@myemail.com"
        message.Subject = "IPCamera Intruder Alert : Motion Detected"
        message.Body = "Motion detected on " + options['camera']

        for img in sc_chain_array[-10:]:
                message.attach(img)

        sc_chain_array = []

        sender = mailer.Mailer(host=options['smtp']['host'],port=options['smtp']['port'],usr=options['smtp']['username'],pwd=options['smtp']['password'])
        sender.send(message)
    else:
        print str(datetime.datetime.now()) + " no images in mailer query"

def check_schedule():
    global options
    current_datetime = datetime.datetime.now()
    hours = options['schedule'][current_datetime.strftime('%a')]
    if int(current_datetime.strftime('%H')) in hours:
        return True
    else:
        return False

def main():
    global options
    global sc_chain_array

    curr_frame = None
    prev_frame = None

    sc_chain = False
    sc_chain_count = 0

    request = urllib2.Request("http://%s/%s" % (options['host'],options['path']))

    if 'login' in options and 'password' in options:
        base64string = base64.encodestring('%s:%s' % (options['login'], options['password'])).replace('\n', '')
        request.add_header("Authorization", "Basic %s" % base64string)

    print str(datetime.datetime.now()) + " starting ipcam security @ " + options['camera']

    timer = RepeatTimer(60*5, mail_timer)
    timer.start()

    while True:

        time.sleep(1)

        now = str(datetime.datetime.now())
        try:
            result = urllib2.urlopen(request)
            curr_frame = Image.open(StringIO.StringIO(result.read()))

            if not prev_frame == None:
                
                try:
                    h = ImageChops.difference(prev_frame, curr_frame)
                except IOError:
                    continue
                    
                diff = ImageStat.Stat(h).rms
                rms = sum(diff)/len(diff)

                if rms > options['sensitivity']:
                    print now + " motion detected"

                    if check_schedule():
                        sc_chain = True
                        sc_chain_count = 0
                        print now + " alarm fired"
                    else:
                        print now + " alarm stays silent, not in schedule"

            # ALARM! ACHTUNG!
            if sc_chain:
                filename = options['save_path']+ now.replace(' ','_') + '.jpg'
                write_sc = open(filename,'w')
                curr_frame.save(write_sc,'jpeg')
                write_sc.close()
                sc_chain_array.append(filename)

                sc_chain_count += 1
                if sc_chain_count > options['photos_in_chain']:
                    sc_chain = False

            prev_frame = curr_frame

        except urllib2.HTTPError:
            continue

if __name__ == '__main__':
    main()